#pragma once
#include <memory>
#include "EventLoop.h"
#include "Socket.h"
#include "Channel.h"
#include "Buffer.h"
#include "Any.h"

typedef enum
{
    DISCONNECTED, // 连接关闭状态
    CONNECTING,   // 连接建立成功 - 待处理状态
    CONNECTED,    // 连接建立完成，各种设置已经完成，可以通信的状态(三次握手完成，连接已建立。)
    DISCONNECTING // 待关闭状态
} ConnStatus;

class Connection;
using PtrConnection = std::shared_ptr<Connection>;
class Connection : public std::enable_shared_from_this<Connection>
{
private:
    uint64_t _conn_id;             // 连接的唯一ID，也是定时器任务的唯一ID，便于连接的管理和查找
    int _sockfd;                   // 当前连接的文件描述符
    bool _enable_inactive_release; // 是否启动非火雨销毁的判断标志，默认false
    EventLoop *_loop;              // 连接所在的EventLoop
    ConnStatus _statu;             // 连接状态
    Socket _socket;                // 套接字管理操作
    Channel _channel;              // 连接事件管理
    Buffer _in_buffer;             // 输入缓冲区 -- 存放从sock中读取到的数据
    Buffer _out_buffer;            // 输出缓冲区 -- 存放要发送给对端的数据
    Any _context;                  // 请求的接收处理上下文

    // 下面这四个回调函数，是让server模块来设置的（服务器模块的处理回调是组件使用者设置的）
    using ConnectedCallback = std::function<void(const PtrConnection &)>;
    using MessageCallback = std::function<void(const PtrConnection &, Buffer *)>;
    using ClosedCallback = std::function<void(const PtrConnection &)>;
    using AnyEventCallback = std::function<void(const PtrConnection &)>;

    // 连接建立成功的时候，要执行的上层用户操作。
    ConnectedCallback _connected_callback;

    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    AnyEventCallback _event_callback;

    // 组件内的连接关闭回调 -- 组件内设置的，因为服务器组件内会把所有的连接管理起来。
    // 一旦某个连接要关闭，就应该从管理的地方移除掉自己的信息。
    ClosedCallback _server_closed_callback;

private:
    // 1. channel事件回调函数
    // Connection 的事件回调函数说明：
    // HandleRead()  → socket 可读（触发上层消息处理）
    // HandleWrite() → socket 可写（继续发送剩余数据）
    // HandleClose() → 客户端断开连接（关闭连接）
    // HandleError() → 系统底层 I/O 错误（释放连接）

    void HandleRead();

    // 当 socket 可写时触发，继续发送 _out_buffer 中未发送完的数据。
    // 数据发送完后自动关闭写事件监听；若处于 DISCONNECTING 状态，发送完成后关闭连接。

    void HandleWrite();
    void HandleClose();
    void HandleError();
    void HandleEvent();

    // 2. 新连接获取之后，设置连接的各个状态
    void EstablishedInLoop();

    // 3. 释放连接接口
    void ReleaseInLoop();

    // 4. 发送数据，但是是把数据写到缓冲区，启动可写事件
    //  为什么要这么做？因为可写条件可能不就绪，即内核缓冲区的数据满了，写不进去了
    void SendInLoop(Buffer buf);

    // 5. 关闭连接释放操作，并非实际的连接释放操作，需要判断还有没有数据待处理，待发送
    void ShutdownInLoop();

    // 6. 启动非活跃连接释放规则
    void EnableInactiveReleaseInLoop(int sec);

    // 7. 取消 非活跃连接释放规则
    void CancelInactiveReleaseInLoop();

    // 8. 切换协议/升级协议
    void UpgradeInLoop(const Any &context,
                       const ConnectedCallback &conn,
                       const MessageCallback &msg,
                       const ClosedCallback &closed,
                       const AnyEventCallback &event);

public:
    Connection(EventLoop *loop, uint64_t conn_id, int sockfd);
    ~Connection();

    // 1. 获取客户端新连接的 fd
    int Fd();

    // 2. 获取连接ID
    int Id();

    // 3. 是否处于CONNECTED状态
    bool Connected();

    // 4. 设置上下文 -- 连接建立完成时进行调用
    void SetContext(const Any &context);

    // 5. 获取上下文
    Any *GetContext();

    // 6. 设置5个回调函数
    void SetConnectedCallback(const ConnectedCallback &cb);
    void SetMessageCallback(const MessageCallback &cb);
    void SetClosedCallback(const ClosedCallback &cb);
    void SetSvrClosedCallback(const ClosedCallback &cb);
    void SetAnyEventCallback(const AnyEventCallback &cb);

    // 7.  连接建立就绪后，进行channel回调设置，启动监控，调用_connected_callback
    void Established();

    // 8. 发送数据，将数据放到缓冲区，启动写事件监控
    void Send(const char *data, size_t len);

    // 9. 提供给组件使用者的关闭接口
    void ShutDown();

    // 10. 释放连接接口
    void Release();

    // 11. 启动非活跃销毁，并定义多长时间无通信就是非活跃，添加定时任务
    void EnableInactiveRelease(int sec);

    // 12. 取消非活跃销毁
    void CancelInactiveRelease();

    // 13. 切换协议
    void Upgrade(const Any &context,
                 const ConnectedCallback &conn,
                 const MessageCallback &msg,
                 const ClosedCallback &closed,
                 const AnyEventCallback &event);
};